package com.jia.train.seat.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jia.train.global.page.PageResponse;
import com.jia.train.global.utils.SnowIdUtil;
import com.jia.train.seat.entity.*;
import com.jia.train.seat.mapper.DailyTrainSeatMapper;
import com.jia.train.seat.mapper.TrainSeatMapper;
import com.jia.train.seat.mapper.TripStationMapper;
import com.jia.train.seat.request.DailyTrainSeatQueryRequest;
import com.jia.train.seat.response.DailyTrainSeatQueryResponse;
import com.jia.train.seat.service.DailyTrainSeatService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Service
public class DailyTrainSeatServiceImpl implements DailyTrainSeatService {

    @Resource
    private DailyTrainSeatMapper dailyTrainSeatMapper;

    @Resource
    private TrainSeatMapper trainSeatMapper;

    @Resource
    private TripStationMapper tripStationMapper;

    public static final Logger logger
            = LoggerFactory.getLogger(DailyTrainSeatServiceImpl.class);


    @Override
    public PageResponse<DailyTrainSeatQueryResponse> selectPage(DailyTrainSeatQueryRequest request) {

        DailyTrainSeatExample DailyTrainSeatExample = new DailyTrainSeatExample();
        // 排序
        DailyTrainSeatExample.setOrderByClause("date desc,trip_code asc,`carriage_index` asc,carriage_seat_index asc");
        // 条件
        DailyTrainSeatExample.Criteria criteria = DailyTrainSeatExample.createCriteria();
        String tripCode = request.getTripCode();
        Date date = request.getDate();
        if (StringUtils.hasText(tripCode)) {
            criteria.andTripCodeEqualTo(tripCode);
        }
        if (ObjectUtil.isNotNull(date)) {
            criteria.andDateEqualTo(date);
        }

        // 构造分页
        PageHelper.startPage(request.getPage(), request.getSize());
        List<DailyTrainSeat> DailyTrainSeats = dailyTrainSeatMapper.selectByExample(DailyTrainSeatExample);
        PageInfo<DailyTrainSeat> pageInfo = new PageInfo<>(DailyTrainSeats);

        List<DailyTrainSeatQueryResponse> list
                = BeanUtil.copyToList(DailyTrainSeats, DailyTrainSeatQueryResponse.class);

        PageResponse<DailyTrainSeatQueryResponse> pageResponse = new PageResponse<>();
        pageResponse.setTotal(pageInfo.getTotal());
        pageResponse.setList(list);
        return pageResponse;
    }

    @Override
    public void deleteDailyTrainSeat(Long id) {
        dailyTrainSeatMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void genDailyTrainSeat(Date date, String tripCode) {

        logger.info("生成日期：{},车次: {} 的座位信息", DateUtil.formatDate(date), tripCode);

        TrainSeatExample trainSeatExample = new TrainSeatExample();
        trainSeatExample.setOrderByClause("`carriage_index` asc,carriage_seat_index asc");
        trainSeatExample.createCriteria()
                .andTripCodeEqualTo(tripCode);

        List<TrainSeat> trainSeats
                = trainSeatMapper.selectByExample(trainSeatExample);

        if (CollectionUtils.isEmpty(trainSeats)) {
            logger.info("车次：{}，没有座位数据，结束生成任务", tripCode);
            return;
        }

        long count = stationCount(tripCode);
        if (count <= 0) {
            logger.info("车次：{}，没有车次车站数据，结束生成任务", tripCode);
        }

        List<DailyTrainSeat> dailyTrainSeatList = new ArrayList<>(trainSeats.size());

        for (TrainSeat trainSeat : trainSeats) {
            DailyTrainSeat dailyTrainSeat
                    = BeanUtil.copyProperties(trainSeat, DailyTrainSeat.class);
            dailyTrainSeat.setId(SnowIdUtil.getLongSnowNextId());
            dailyTrainSeat.setCreateTime(new DateTime());
            dailyTrainSeat.setDate(date);
            dailyTrainSeat.setSell(StrUtil.fillBefore("", '0', Math.toIntExact(count - 1)));
            dailyTrainSeatList.add(dailyTrainSeat);
        }

        DailyTrainSeatExample dailyTrainSeatExample = new DailyTrainSeatExample();
        DailyTrainSeatExample.Criteria criteria = dailyTrainSeatExample.createCriteria();
        criteria.andTripCodeEqualTo(tripCode);
        criteria.andDateEqualTo(date);

        dailyTrainSeatMapper.deleteByExample(dailyTrainSeatExample);
        List<List<?>> lists = splitList(dailyTrainSeatList);
        for (List<?> list : lists) {
            dailyTrainSeatMapper.batchInsert(list);
        }

    }

    @Override
    public List<DailyTrainSeat> selectByCarriage(Date date, String code, Integer index) {
        DailyTrainSeatExample dailyTrainSeatExample = new DailyTrainSeatExample();
        dailyTrainSeatExample.setOrderByClause("carriage_seat_index asc");
        DailyTrainSeatExample.Criteria criteria = dailyTrainSeatExample.createCriteria();
        criteria.andDateEqualTo(date);
        criteria.andTripCodeEqualTo(code);
        criteria.andCarriageIndexEqualTo(index);
        return dailyTrainSeatMapper.selectByExample(dailyTrainSeatExample);
    }


    private long stationCount(String tripCode) {
        TripStationExample tripStationExample = new TripStationExample();
        TripStationExample.Criteria criteria = tripStationExample.createCriteria();
        criteria.andTripCodeEqualTo(tripCode);
        return tripStationMapper.countByExample(tripStationExample);
    }

    /**
     * 三分数组
     *
     * @param splitList 数组
     * @return 数组
     */
    public List<List<?>> splitList(List<?> splitList) {
        Assert.noNullElements(splitList, "Arrays cannot be empty");
        int size = splitList.size();
        List<List<?>> resultList = new ArrayList<>(3);
        if (size <= 3) {
            return Collections.singletonList(splitList);
        }
        int start = size / 3;
        List<?> part1 = splitList.subList(0, start);
        resultList.add(part1);
        List<?> part2 = splitList.subList(start, Math.min(2 * start, size));
        resultList.add(part2);
        List<?> part3 = splitList.subList(start * 2, size);
        resultList.add(part3);
        return resultList;
    }

}
